home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / diskcheck.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  4KB  |  204 lines

  1. /* diskcheck - test a disk for bad blocks    Author: Andy Tanenbaum */
  2.  
  3. #include <sys/types.h>
  4. #include <signal.h>
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8.  
  9. #include <minix/config.h>
  10. #include <minix/const.h>
  11.  
  12. #undef printf
  13. #define OK 0
  14. #define PRINTFREQ  10
  15. #define N 30
  16.  
  17. char purgebuf[BLOCK_SIZE * N];
  18. char buf[BLOCK_SIZE], zero[BLOCK_SIZE];
  19. int pat1[BLOCK_SIZE / 2], pat2[BLOCK_SIZE / 2];
  20. int blk = -1;            /* number of the block in buf, or -1 */
  21. int pfd;            /* file descriptor for purging */
  22. int fd;                /* file descriptor for data I/O */
  23. unsigned initblock;        /* first block to test */
  24. unsigned curblock;        /* current block */
  25. unsigned limit;            /* first block beyond test zone */
  26. unsigned errors;        /* # errors so far */
  27. unsigned ct;            /* # blocks read so far */
  28. int intflag;            /* set when signal seen */
  29. extern errno;
  30. long pos;
  31. char *purgefile = "/dev/ram";
  32.  
  33. main(argc, argv)
  34. int argc;
  35. char *argv[];
  36. {
  37.   unsigned b;
  38.   int i;
  39.   void catch();
  40.  
  41.   signal(SIGINT, catch);
  42.   signal(SIGQUIT, catch);
  43.   if (argc != 4) usage();
  44.   if ((fd = open(argv[1], O_RDWR)) < 0) {
  45.     printf("Cannot open %s\n", argv[1]);
  46.     exit(1);
  47.   }
  48.   if ((pfd = open(purgefile, O_RDWR)) < 0) {
  49.     printf("Cannot open %s\n", purgefile);
  50.     exit(1);
  51.   }
  52.   initblock = atoi(argv[2]);
  53.   limit = initblock + atoi(argv[3]);
  54.   if (limit <= initblock) usage();
  55.  
  56.   for (i = 0; i < BLOCK_SIZE / 2; i++) {
  57.     pat1[i] = i;
  58.     pat2[i] = 1000 - i;
  59.   }
  60.  
  61.   for (b = initblock; b < limit; b++) {
  62.     if (intflag) break;
  63.     if (testblock(b) == ERROR) {
  64.         errors++;
  65.         if (blk == b) {
  66.             /* Read ok, write failed; try to restore block. */
  67.             lseek(fd, pos, SEEK_SET);
  68.             write(fd, buf, BLOCK_SIZE);
  69.         }
  70.     }
  71.     curblock = b;
  72.     ct++;
  73.     if (ct % PRINTFREQ == 0) status();
  74.   }
  75.  
  76.   status();
  77.   exit(0);
  78. }
  79.  
  80.  
  81. int testblock(b)
  82. unsigned b;
  83. {
  84. /* Read block b in, save it in buf.  Then overwrite that block with a
  85.  * known test pattern and read it back.  Finally, replace the block.
  86.  * Return OK or ERROR.
  87.  */
  88.  
  89.   int s;
  90.  
  91.   blk = -1;
  92.   pos = (long) BLOCK_SIZE *(long) b;
  93.   purge_cache();
  94.   if (lseek(fd, pos, SEEK_SET) != pos) fatal("Cannot seek to block ", b);
  95.  
  96.   /* Read block b into 'buf'. */
  97.   s = read(fd, buf, BLOCK_SIZE);
  98.  
  99.   /* Test for various outcomes of the read. */
  100.   if (s == BLOCK_SIZE) {
  101.     blk = b;
  102.     if (wtest(pos, pat1) == ERROR) return(ERROR);
  103.     if (wtest(pos, pat2) == ERROR) return (ERROR);
  104.     lseek(fd, pos, SEEK_SET);
  105.     if (write(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) {
  106.         nonfatal("Cannot rewrite block ", b);
  107.         return(ERROR);
  108.     } else {
  109.         return(OK);
  110.     }
  111.   }
  112.   if (s < 0) {
  113.     if (errno == EIO)
  114.         nonfatal("Read error on block ", b);
  115.     else {
  116.         printf("\nError.  Read returned %d.  errno=%d.   ", s, errno);
  117.         fatal("Block ", b);
  118.     }
  119.     return(ERROR);
  120.   }
  121.   if (s == 0) fatal("End of file reached trying to read block ", b);
  122.  
  123.  
  124.   nonfatal("Read size error on block ", b);
  125. }
  126.  
  127. status()
  128. {
  129.   printf("%8u blocks tested, %u errors detected (last block tested = %5u)\r",
  130.          ct, errors, curblock);
  131. }
  132.  
  133. nonfatal(s, b)
  134. char *s;
  135. unsigned b;
  136. {
  137.   printf("\n%s%u\n", s, b);
  138. }
  139.  
  140. fatal(s, b)
  141. char *s;
  142. unsigned b;
  143. {
  144.   printf("\n%s%u\n", s, b);
  145.   status();
  146.   exit(1);
  147. }
  148.  
  149.  
  150. void catch(sig)
  151. int sig;            /* prototype says there has to be 1 arg */
  152. {
  153.   signal(SIGINT, catch);
  154.   signal(SIGQUIT, catch);
  155.   intflag = 1;
  156. }
  157.  
  158.  
  159. usage()
  160. {
  161.   printf("Usage: diskcheck device start-block block-count\n");
  162.   exit(1);
  163. }
  164.  
  165. wtest(pos, pat)
  166. long pos;
  167. int pat[];
  168. {
  169.   int testb[BLOCK_SIZE / 2];
  170.   int i;
  171.  
  172.   lseek(fd, pos, SEEK_SET);
  173.   if (write(fd, (char *) pat, BLOCK_SIZE) != BLOCK_SIZE) return(ERROR);
  174.   sync();            /* force the write to the disk */
  175.   purge_cache();
  176.   lseek(fd, pos, SEEK_SET);
  177.   if (read(fd, (char *) testb, BLOCK_SIZE) != BLOCK_SIZE) return(ERROR);
  178.   for (i = 0; i < BLOCK_SIZE / 2; i++)
  179.     if (testb[i] != pat[i]) {
  180.         printf("%d %d\n", testb[i], pat[i]);
  181.         return(ERROR);
  182.     }
  183.   return(OK);
  184. }
  185.  
  186. purge_cache()
  187. {
  188. /* Do enough reads that the cache is purged. */
  189.  
  190.   int left, count, r;
  191.  
  192.   pfd = open(purgefile, O_RDONLY);
  193.   left = NR_BUFS;
  194.   while (left > 0) {
  195.     count = (left < N ? left : N);
  196.     if ((r = read(pfd, purgebuf, count * BLOCK_SIZE)) != count * BLOCK_SIZE) {
  197.         printf("ERROR: count=%d  left=%d r=%d.  ", count, left, r);
  198.         fatal("Cannot purge cache.  errno= ", errno);
  199.     }
  200.     left -= count;
  201.   }
  202.   close(pfd);
  203. }
  204.